﻿// -----------------------------------------------------------------------
// <copyright file="DbValue.cs" company="JSC Centido">
//  Copyright (c) JSC Centido. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------

using System.Data.Common;

namespace Centido.Core
{
    using System;
    using System.Diagnostics.CodeAnalysis;

    /// <summary>
    ///   Database value converters.
    /// </summary>
    [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Db")]
    public static class DbValue
    {
        /// <summary>
        ///   Convertes a value from a database to a string.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted string value.</returns>
        public static string GetString(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetString(columnValue.Value);

            return Convert.ToString(dbValue);
        }


        /// <summary>
        ///   Converts a database column value to a string.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted string value.</returns>
        public static string GetString(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetString(columnValue.Value);
        }


        /// <summary>
        ///   Retrieves a parameter value and converts it to a string.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted string value.</returns>
        public static string GetString(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetString(reader[parameterName]);
        }


        /// <summary>
        ///   Convertes a value from a database to an integer.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted integer value or null.</returns>
        public static int? GetInteger(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetInteger(columnValue.Value);

            return Convert.ToInt32(dbValue);
        }


        /// <summary>
        ///   Converts a database column value to an integer.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted integer value or null.</returns>
        public static int? GetInteger(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetInteger(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to an integer.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted integer value.</returns>
        public static int? GetInteger(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetInteger(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a small integer.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted small integer value or null.</returns>
        public static short? GetSmallInteger(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetSmallInteger(columnValue.Value);

            return Convert.ToInt16(dbValue);
        }

        /// <summary>
        ///   Converts a database column value to a small integer.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted small integer value or null.</returns>
        public static short? GetSmallInteger(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetSmallInteger(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a small integer.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted small integer value.</returns>
        public static short? GetSmallInteger(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetSmallInteger(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a big integer.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted big integer value or null.</returns>
        public static long? GetBigInteger(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetBigInteger(columnValue.Value);

            return Convert.ToInt64(dbValue);
        }

        /// <summary>
        ///   Converts a database column value to a big integer.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted big integer value or null.</returns>
        public static long? GetBigInteger(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetBigInteger(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a big integer.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted big integer value.</returns>
        public static long? GetBigInteger(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetBigInteger(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a binary.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted binary value or null.</returns>
        public static byte[] GetBinary(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetBinary(columnValue.Value);

            return (byte[])dbValue;
        }

        /// <summary>
        ///   Converts a database column value to a binary.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted binary value or null.</returns>
        public static byte[] GetBinary(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetBinary(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a binary.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted binary value.</returns>
        public static byte[] GetBinary(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetBinary(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a boolean.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted boolean value or null.</returns>
        public static bool? GetBoolean(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetBoolean(columnValue.Value);

            if (dbValue is short)
                return (short)dbValue == 1;

            return Convert.ToBoolean(dbValue);
        }

        /// <summary>
        ///   Converts a database column value to a boolean.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted boolean value or null.</returns>
        public static bool? GetBoolean(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetBoolean(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a boolean.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted boolean value.</returns>
        public static bool? GetBoolean(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetBoolean(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a datetime.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted datetime value or null.</returns>
        public static DateTime? GetDateTime(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetDateTime(columnValue.Value);

            return Convert.ToDateTime(dbValue);
        }

        /// <summary>
        ///   Converts a database column value to a datetime.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted datetime value or null.</returns>
        public static DateTime? GetDateTime(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetDateTime(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a datetime.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted datetime value.</returns>
        public static DateTime? GetDateTime(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetDateTime(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a decimal.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted decimal value or null.</returns>
        public static decimal? GetDecimal(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetDecimal(columnValue.Value);

            return Convert.ToDecimal(dbValue);
        }

        /// <summary>
        ///   Converts a database column value to a decimal.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted decimal value or null.</returns>
        public static decimal? GetDecimal(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetDecimal(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a decimal.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted decimal value.</returns>
        public static decimal? GetDecimal(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetDecimal(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a guid.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted guid value or null.</returns>
        public static Guid? GetGuid(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetGuid(columnValue.Value);

            // Testing if this is byte array
            var byteArray = dbValue as byte[];

            if (byteArray != null)
                return new Guid(byteArray);

            return (Guid)dbValue;
        }

        /// <summary>
        ///   Converts a database column value to a guid.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted guid value or null.</returns>
        public static Guid? GetGuid(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetGuid(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a guid.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted guid value.</returns>
        public static Guid? GetGuid(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetGuid(reader[parameterName]);
        }

        /// <summary>
        ///   Converts a database column value to a timespan.
        /// </summary>
        /// <param name = "dbValue">The database value.</param>
        /// <returns>Returns the converted timespan value or null.</returns>
        public static TimeSpan? GetTimeSpan(object dbValue)
        {
            if (dbValue == null)
                return null;
            if (dbValue == DBNull.Value)
                return null;

            // Testing if this a column value
            var columnValue = dbValue as ColumnValue;

            if (columnValue != null)
                return GetTimeSpan(columnValue.Value);

            if (dbValue is decimal || dbValue is long)
                return TimeSpan.FromTicks(Convert.ToInt64(dbValue));

            return (TimeSpan)dbValue;
        }

        /// <summary>
        ///   Converts a database column value to a timespan.
        /// </summary>
        /// <param name="columnValue">The database column value.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="columnValue"/> is null.</exception>
        /// <returns>Returns the converted timespan value or null.</returns>
        public static TimeSpan? GetTimeSpan(this ColumnValue columnValue)
        {
            if (columnValue == null)
                throw new ArgumentNullException("columnValue");

            return GetTimeSpan(columnValue.Value);
        }

        /// <summary>
        ///   Retrieves a parameter value and converts it to a timespan.
        /// </summary>
        /// <param name="reader">The database reader.</param>
        /// <param name="parameterName">The name of the parameter.</param>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="reader"/> is null.</exception>
        /// <exception cref="ArgumentNullException">Thrown when the value of <paramref name="parameterName"/> is null.</exception>
        /// <returns>Returns the converted timespan value.</returns>
        public static TimeSpan? GetTimeSpan(this DbDataReader reader, string parameterName)
        {
            if (reader == null)
                throw new ArgumentNullException("reader");
            if (parameterName == null)
                throw new ArgumentNullException("parameterName");

            return GetTimeSpan(reader[parameterName]);
        }

        /// <summary>
        ///   Get db value
        /// </summary>
        /// <param name = "dbValue">Value</param>
        /// <returns>Db value</returns>
        public static object GetDbValue(object dbValue)
        {
            if (dbValue == null)
                return DBNull.Value;

            // If this is a guid value
            if (dbValue is Guid)
                return ((Guid)dbValue).ToByteArray();

            // If this is a timespan value
            if (dbValue is TimeSpan)
                return ((TimeSpan)dbValue).Ticks;

            return dbValue;
        }
    }
}